using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Collections.Concurrent;
using LDNS.Models;
using NLog;

namespace LDNS.Utilities
{
    /// <summary>
    /// DNS记录管理器（合并版本）
    /// 作者：huobing
    /// 功能：整合DNS记录的内存管理、配置文件管理、监控和域名解析功能
    /// </summary>
    public class DnsRecordManager
    {
        /// <summary>
        /// 日志记录器
        /// </summary>
        private readonly Logger _logger = LogManager.GetCurrentClassLogger();
        // 单例实例字段
        private static DnsRecordManager? _instance;
        private static readonly object _instanceLock = new();
        private static string? _instanceConfigPath;
        private static int _instanceWatchInterval = 0;
        
        /// <summary>
        /// 获取单例实例（带参数）
        /// 作者：huobing
        /// </summary>
        /// <param name="recordConfigFilePath">记录配置文件路径</param>
        /// <param name="watchIntervalSeconds">监控间隔（秒），用于变更事件的防抖延迟</param>
        /// <returns>DnsRecordManager单例实例</returns>
        public static DnsRecordManager GetInstance(string recordConfigFilePath, int watchIntervalSeconds = 0)
        {
            lock (_instanceLock)
            {
                // 如果实例不存在，或者参数发生变化，则重新创建实例
                if (_instance == null || _instanceConfigPath != recordConfigFilePath || _instanceWatchInterval != watchIntervalSeconds)
                {
                    _instance = new DnsRecordManager(recordConfigFilePath, watchIntervalSeconds);
                    _instanceConfigPath = recordConfigFilePath;
                    _instanceWatchInterval = watchIntervalSeconds;
                }
                return _instance;
            }
        }
        
        /// <summary>
        /// 获取当前单例实例（如果已创建）
        /// 作者：huobing
        /// </summary>
        public static DnsRecordManager Instance
        {
            get
            {
                lock (_instanceLock)
                {
                    return _instance ?? throw new InvalidOperationException("DnsRecordManager实例未初始化");
                }
            }
        }
        
        /// <summary>
        /// DNS记录字典（并发安全）
        /// </summary>
        private readonly ConcurrentDictionary<string, DnsRecord> _dnsRecords = new();

        /// <summary>
        /// 配置文件路径
        /// </summary>
        private readonly string? _configFilePath;
        
        /// <summary>
        /// 文件系统监控器
        /// </summary>
        private FileSystemWatcher? _fileWatcher;
        
        /// <summary>
        /// 是否正在监控
        /// </summary>
        private bool _isWatching = false;
        
        /// <summary>
        /// 防抖延迟（毫秒）
        /// </summary>
        private int _debounceDelayMs = 100;

        /// <summary>
        /// 获取所有DNS记录
        /// </summary>
        public IReadOnlyDictionary<string, DnsRecord> DnsRecords => _dnsRecords;
        
        /// <summary>
        /// 获取DNS记录数量
        /// </summary>
        public int DnsRecordsCount => _dnsRecords.Count;
        
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="recordConfigFilePath">记录配置文件路径</param>
        public DnsRecordManager(string recordConfigFilePath)
        {
            _configFilePath = recordConfigFilePath;
            LoadConfig();
        }

        /// <summary>
        /// 构造函数（支持监控间隔配置）
        /// </summary>
        /// <param name="recordConfigFilePath">记录配置文件路径</param>
        /// <param name="watchIntervalSeconds">监控间隔（秒），用于变更事件的防抖延迟</param>
        public DnsRecordManager(string recordConfigFilePath, int watchIntervalSeconds)
            : this(recordConfigFilePath)
        {
            _debounceDelayMs = Math.Max(100, watchIntervalSeconds * 1000);
        }
        
        /// <summary>
        /// 加载配置文件
        /// </summary>
        public void LoadConfig()
        {
            try
            {
                // 临时存储新记录
                var tempRecords = new ConcurrentDictionary<string, DnsRecord>();
                
                // 加载配置文件
                if (File.Exists(_configFilePath))
                {
                    var lines = File.ReadAllLines(_configFilePath);
                    foreach (var line in lines)
                    {
                        if (string.IsNullOrWhiteSpace(line) || line.TrimStart().StartsWith("#"))
                            continue;
                          
                        var parts = line.Split([' ', '\t'], StringSplitOptions.RemoveEmptyEntries);
                        if (parts.Length >= 2)
                        {
                            var record = new DnsRecord
                            {
                                IP = parts[0].Trim(),
                                Domain = parts[1].Trim(),
                                RecordType = parts.Length > 2 ? parts[2].Trim() : "A",
                                Ttl = parts.Length > 3 && int.TryParse(parts[3].Trim(), out int ttl) ? ttl : 3600,
                                Description = string.Empty,
                                IsEnabled = true,
                                CreatedTime = DateTime.Now
                            };
                            
                            var recordKey = $"{record.Domain.ToLower()}:{record.RecordType}";
                            tempRecords[recordKey] = record;
                        }
                    }
                }
                else
                {
                    _logger?.Info($"DNS记录配置文件不存在: {_configFilePath}");
                }
                
                // 添加默认的本地记录
                var localhostRecord = new DnsRecord
                {
                    IP = "127.0.0.1",
                    Domain = "localhost",
                    RecordType = "A",
                    Ttl = 3600,
                    Description = string.Empty,
                    IsEnabled = true,
                    CreatedTime = DateTime.Now
                };
                var localhostKey = $"{localhostRecord.Domain.ToLower()}:{localhostRecord.RecordType}";
                tempRecords[localhostKey] = localhostRecord;
                
                // 替换内存中的记录
                _dnsRecords.Clear();
                foreach (var kvp in tempRecords)
                {
                    _dnsRecords[kvp.Key] = kvp.Value;
                }
                
                _logger?.Info($"已加载 {_dnsRecords.Count} 条DNS记录配置");
            }
            catch (Exception ex)
            {
                _logger?.Error(ex, $"加载DNS记录配置文件失败: {ex.Message}");
            }
        }
        
        /// <summary>
        /// 开始监控配置文件变化
        /// </summary>
        public void StartWatching()
        {
            if (_isWatching) return;
            
            try
            {
                var dir = Path.GetDirectoryName(_configFilePath) ?? ".";
                var name = Path.GetFileName(_configFilePath) ?? "dns.conf";
                _fileWatcher = new FileSystemWatcher(dir, name)
                {
                    NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.Size,
                    EnableRaisingEvents = true
                };
                _fileWatcher.Changed += OnConfigFileChanged;
                
                _isWatching = true;
                _logger?.Info($"开始监控DNS记录配置文件: {_configFilePath}");
            }
            catch (Exception ex)
            {
                _logger.Error(ex, $"启动配置文件监控失败: {ex.Message}");
            }
        }
        
        /// <summary>
        /// 停止监控配置文件变化
        /// </summary>
        public void StopWatching()
        {
            if (!_isWatching) return;
            
            try
            {
                if (_fileWatcher != null)
                {
                    _fileWatcher.EnableRaisingEvents = false;
                    _fileWatcher.Changed -= OnConfigFileChanged;
                    _fileWatcher.Dispose();
                    _fileWatcher = null;
                }
                
                _isWatching = false;
                _logger?.Info("停止监控DNS记录配置文件");
            }
            catch (Exception ex)
            {
                _logger?.Error(ex, $"停止监控失败: {ex.Message}");
            }
        }
        
        /// <summary>
        /// 配置文件变化事件处理
        /// </summary>
        private void OnConfigFileChanged(object sender, FileSystemEventArgs e)
        {
            // 延迟加载以避免文件被占用（可配置防抖延迟）
            System.Threading.Thread.Sleep(_debounceDelayMs);
            _logger?.Info($"检测到DNS记录配置文件变化: {e.FullPath}");
            LoadConfig();
        }
        
        /// <summary>
        /// 根据域名查找匹配的IP地址
        /// </summary>
        /// <param name="domain">域名</param>
        /// <param name="recordType">记录类型（默认为A）</param>
        /// <returns>匹配的IP地址，未找到返回null</returns>
        public string? ResolveDomain(string domain, string recordType = "A")
        {
            try
            {
                // 精确匹配
                var exactKey = $"{domain.ToLower()}:{recordType}";
                if (_dnsRecords.TryGetValue(exactKey, out var exactRecord) && exactRecord.IsEnabled)
                {
                    return exactRecord.IP;
                }
                
                // 通配符匹配（如果存在通配符记录）
                foreach (var record in _dnsRecords.Values.Where(r => r.IsEnabled && r.RecordType.Equals(recordType, StringComparison.OrdinalIgnoreCase)))
                {
                    if (record.Domain.StartsWith("*") && domain.EndsWith(record.Domain[1..]))
                    {
                        return record.IP;
                    }
                }
                
                return null;
            }
            catch (Exception ex)
            {
                _logger?.Error(ex, $"解析域名失败: {domain}");
                return null;
            }
        }
        
        /// <summary>
        /// 添加DNS记录
        /// </summary>
        /// <param name="domain">域名</param>
        /// <param name="ip">IP地址</param>
        /// <param name="recordType">记录类型</param>
        /// <param name="ttl">生存时间（秒）</param>
        /// <param name="description">记录描述</param>
        /// <returns>是否添加成功</returns>
        public bool AddDnsRecord(string domain, string ip, string recordType, int ttl, string description)
        {
            if (string.IsNullOrWhiteSpace(domain) || string.IsNullOrWhiteSpace(ip))
            {
                return false;
            }

            try
            {
                var recordKey = $"{domain.ToLower()}:{recordType}";
                var dnsRecord = new DnsRecord
                {
                    Domain = domain,
                    IP = ip,
                    RecordType = recordType,
                    Ttl = ttl,
                    Description = description,
                    CreatedTime = DateTime.Now,
                    IsEnabled = true
                };

                _dnsRecords[recordKey] = dnsRecord;
                _logger.Info($"添加DNS记录: {domain} ({recordType}) -> {ip}, TTL: {ttl}");
                return true;
            }
            catch (Exception ex)
            {
                _logger.Error(ex, $"添加DNS记录失败: {ex.Message}");
                return false;
            }
        }

        /// <summary>
        /// 移除DNS记录
        /// </summary>
        /// <param name="domain">域名</param>
        /// <param name="recordType">记录类型</param>
        /// <returns>是否移除成功</returns>
        public bool RemoveDnsRecord(string domain, string recordType = "A")
        {
            if (string.IsNullOrWhiteSpace(domain))
            {
                return false;
            }

            try
            {
                var recordKey = $"{domain.ToLower()}:{recordType}";
                bool removed = _dnsRecords.TryRemove(recordKey, out _);
                
                if (removed)
                {
                    _logger.Info($"移除DNS记录: {domain} ({recordType})");
                }

                return removed;
            }
            catch (Exception ex)
            {
                _logger.Error(ex, $"移除DNS记录失败: {ex.Message}");
                return false;
            }
        }

        /// <summary>
        /// 清除所有DNS记录
        /// </summary>
        public void ClearDnsRecords()
        {
            try
            {
                _dnsRecords.Clear();
                _logger.Info("已清除所有DNS记录");
            }
            catch (Exception ex)
            {
                _logger.Error(ex, $"清除DNS记录失败: {ex.Message}");
            }
        }

        /// <summary>
        /// 获取所有DNS记录
        /// </summary>
        /// <returns>DNS记录列表</returns>
        public List<DnsRecord> GetDnsRecords()
        {
            return [.. _dnsRecords.Values];
        }

        /// <summary>
        /// 获取DNS记录统计信息
        /// </summary>
        /// <returns>记录统计信息</returns>
        public DnsRecordStatistics GetDnsRecordStatistics()
        {
            var statistics = new DnsRecordStatistics
            {
                TotalRecords = _dnsRecords.Count,
                ARecordCount = _dnsRecords.Values.Count(r => r.RecordType == "A"),
                CnameRecordCount = _dnsRecords.Values.Count(r => r.RecordType == "CNAME"),
                MxRecordCount = _dnsRecords.Values.Count(r => r.RecordType == "MX"),
                LastUpdated = DateTime.Now
            };
            return statistics;
        }
        
        /// <summary>
        /// 保存配置到文件
        /// </summary>
        public void SaveConfig()
        {
            if (!DnsConfigManager.Instance.Config.EnableRecordPersistence)
            {
                return;
            }
            try
            {
                var lines = new List<string>{
                        "# DNS记录配置文件",
                        "# 格式：IP地址 域名模式 [记录类型] [TTL]",
                        "# 支持通配符 * 匹配任意子域名",
                        ""
                    };
                    
                    foreach (var record in _dnsRecords.Values.Where(r => r.IsEnabled))
                    {
                        var line = $"{record.IP} {record.Domain}";
                        if (record.RecordType != "A")
                            line += $" {record.RecordType}";
                        if (record.Ttl != 3600)
                            line += $" {record.Ttl}";
                        
                        lines.Add(line);
                    }
                    
                    if (!string.IsNullOrEmpty(_configFilePath))
                    {
                        var dir = Path.GetDirectoryName(_configFilePath);
                        if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir)) Directory.CreateDirectory(dir);
                        File.WriteAllLines(_configFilePath, lines);
                        _logger?.Info($"DNS记录配置已保存到: {_configFilePath}");
                    }
                    else
                    {
                        _logger?.Error("无法保存DNS记录配置: 配置文件路径为空");
                    }
            }
            catch (Exception ex)
            {
                _logger?.Error(ex, $"保存DNS记录配置失败: {ex.Message}");
            }
        }
    }
}